Adding back guest MSI eoi support for unmaskable MSI interrupt
authorShan Haitao <haitao.shan@intel.com>
Tue, 19 Jul 2011 07:24:19 +0000 (08:24 +0100)
committerShan Haitao <haitao.shan@intel.com>
Tue, 19 Jul 2011 07:24:19 +0000 (08:24 +0100)
This patch adds back proper guest MSI EOI hook for correctly handling
unmaskable MSI interrupt, which is wrongly removed by changset 23703.

Signed-off-by: Shan Haitao <haitao.shan@intel.com>
xen/arch/x86/hvm/vlapic.c
xen/drivers/passthrough/io.c
xen/include/asm-x86/hvm/io.h

index fabe0e91e8464436bcdb8ea314f1ebeedd6bc490..8b05f1adc394a7bfe97d9abe847c64b3aa6fda52 100644 (file)
@@ -400,6 +400,8 @@ void vlapic_EOI_set(struct vlapic *vlapic)
 
     if ( vlapic_test_and_clear_vector(vector, &vlapic->regs->data[APIC_TMR]) )
         vioapic_update_EOI(vlapic_domain(vlapic), vector);
+
+    hvm_dpci_msi_eoi(current->domain, vector);
 }
 
 int vlapic_ipi(
index bce86adafc757df342096bab86737d7c0af5c8cf..44c89365b45ab157132e11fe52486f8074e2436b 100644 (file)
@@ -421,6 +421,56 @@ int hvm_do_IRQ_dpci(struct domain *d, struct pirq *pirq)
 }
 
 #ifdef SUPPORT_MSI_REMAPPING
+/* called with d->event_lock held */
+static void __msi_pirq_eoi(struct hvm_pirq_dpci *pirq_dpci)
+{
+    irq_desc_t *desc;
+
+    if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) &&
+         (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) )
+    {
+        struct pirq *pirq = dpci_pirq(pirq_dpci);
+
+        BUG_ON(!local_irq_is_enabled());
+        desc = pirq_spin_lock_irq_desc(pirq, NULL);
+        if ( !desc )
+            return;
+        desc_guest_eoi(desc, pirq);
+    }
+}
+
+static int _hvm_dpci_msi_eoi(struct domain *d,
+                             struct hvm_pirq_dpci *pirq_dpci, void *arg)
+{
+    int vector = (long)arg;
+
+    if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) &&
+         (pirq_dpci->gmsi.gvec == vector) )
+    {
+        int dest = pirq_dpci->gmsi.gflags & VMSI_DEST_ID_MASK;
+        int dest_mode = !!(pirq_dpci->gmsi.gflags & VMSI_DM_MASK);
+
+        if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest,
+                               dest_mode) )
+        {
+            __msi_pirq_eoi(pirq_dpci);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void hvm_dpci_msi_eoi(struct domain *d, int vector)
+{
+    if ( !iommu_enabled || !d->arch.hvm_domain.irq.dpci )
+       return;
+
+    spin_lock(&d->event_lock);
+    pt_pirq_iterate(d, _hvm_dpci_msi_eoi, (void *)(long)vector);
+    spin_unlock(&d->event_lock);
+}
+
 static int hvm_pci_msi_assert(struct domain *d,
                               struct hvm_pirq_dpci *pirq_dpci)
 {
@@ -458,6 +508,14 @@ static int _hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci,
             else
                 hvm_pci_intx_assert(d, device, intx);
             pirq_dpci->pending++;
+
+#ifdef SUPPORT_MSI_REMAPPING
+            if ( pirq_dpci->flags & HVM_IRQ_DPCI_TRANSLATE )
+            {
+                /* for translated MSI to INTx interrupt, eoi as early as possible */
+                __msi_pirq_eoi(pirq_dpci);
+            }
+#endif
         }
 
         /*
index 419f25f41f62f5e8c225f38a3987b708dd3625d2..ce2bcb373fb6e7787dd0f1cef75c15291f6e48df 100644 (file)
@@ -139,5 +139,6 @@ struct hvm_hw_stdvga {
 void stdvga_init(struct domain *d);
 void stdvga_deinit(struct domain *d);
 
+extern void hvm_dpci_msi_eoi(struct domain *d, int vector);
 #endif /* __ASM_X86_HVM_IO_H__ */